package rad.framework.uml2.uml.edit.providers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.command.MoveCommand;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emf.edit.command.ReplaceCommand;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
import org.eclipse.emf.edit.provider.ReflectiveItemProvider;
import org.eclipse.emf.edit.provider.ViewerNotification;
import org.eclipse.uml2.uml.Extension;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.util.UMLUtil;

import rad.framework.uml2.uml.edit.UMLEditPlugin;

/**
 * @author boudyacho
 * 
 */
public class StereotypeApplicationItemProvider extends ReflectiveItemProvider {

	/**
	 * @param adapterFactory
	 */
	public StereotypeApplicationItemProvider(AdapterFactory adapterFactory) {
		super(adapterFactory);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ItemProviderAdapter#createAddCommand(org
	 * .eclipse.emf.edit.domain.EditingDomain, org.eclipse.emf.ecore.EObject,
	 * org.eclipse.emf.ecore.EStructuralFeature, java.util.Collection, int)
	 */
	@Override
	protected Command createAddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection collection, int index) {
		return new AddCommand(domain, owner, feature, collection, index) {

			@Override
			public Collection doGetAffectedObjects() {
				return Collections.singleton(UMLUtil.getBaseElement(owner));
			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ItemProviderAdapter#createMoveCommand(org
	 * .eclipse.emf.edit.domain.EditingDomain, org.eclipse.emf.ecore.EObject,
	 * org.eclipse.emf.ecore.EStructuralFeature, java.lang.Object, int)
	 */
	@Override
	protected Command createMoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object value, int index) {
		return new MoveCommand(domain, owner, feature, value, index) {

			@Override
			public Collection doGetAffectedObjects() {
				return Collections.singleton(UMLUtil.getBaseElement(owner));
			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ItemProviderAdapter#createRemoveCommand
	 * (org.eclipse.emf.edit.domain.EditingDomain,
	 * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EStructuralFeature,
	 * java.util.Collection)
	 */
	@Override
	protected Command createRemoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection collection) {
		return new RemoveCommand(domain, owner, feature, collection) {

			@Override
			public Collection doGetAffectedObjects() {
				return Collections.singleton(UMLUtil.getBaseElement(owner));
			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ItemProviderAdapter#createReplaceCommand
	 * (org.eclipse.emf.edit.domain.EditingDomain,
	 * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EStructuralFeature,
	 * org.eclipse.emf.ecore.EObject, java.util.Collection)
	 */
	@Override
	protected Command createReplaceCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, EObject value, Collection collection) {
		return new ReplaceCommand(domain, owner, feature, value, collection) {

			@Override
			public Collection doGetAffectedObjects() {
				return Collections.singleton(UMLUtil.getBaseElement(owner));
			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ItemProviderAdapter#createSetCommand(org
	 * .eclipse.emf.edit.domain.EditingDomain, org.eclipse.emf.ecore.EObject,
	 * org.eclipse.emf.ecore.EStructuralFeature, java.lang.Object, int)
	 */
	@Override
	protected Command createSetCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object value, int index) {

		if (index == CommandParameter.NO_INDEX) {
			return createSetCommand(domain, owner, feature, value);
		}

		return new SetCommand(domain, owner, feature, value, index) {

			@Override
			public Collection doGetAffectedObjects() {
				return Collections.singleton(UMLUtil.getBaseElement(owner));
			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ReflectiveItemProvider#getPropertyDescriptors
	 * (java.lang.Object)
	 */
	@Override
	public List getPropertyDescriptors(Object object) {
		itemPropertyDescriptors = new ArrayList();

		for (Iterator eAllStructuralFeatures = ((EObject) object).eClass().getEAllStructuralFeatures().iterator(); eAllStructuralFeatures.hasNext();) {

			EStructuralFeature.Internal eStructuralFeature = (EStructuralFeature.Internal) eAllStructuralFeatures.next();
			boolean isBaseReference = eStructuralFeature.getName().startsWith(Extension.METACLASS_ROLE_PREFIX);
			String[] filterFlags = isBaseReference || eStructuralFeature.isContainment() ? new String[] { "org.eclipse.ui.views.properties.expert" } : null;

			itemPropertyDescriptors.add(new UMLItemPropertyDescriptor(((ComposeableAdapterFactory) adapterFactory).getRootAdapterFactory(), null, getFeatureText(eStructuralFeature), getResourceLocator().getString("_UI_Property_description",
					new Object[] { getFeatureText(eStructuralFeature), eStructuralFeature.getEType().getName() }), eStructuralFeature, !isBaseReference && eStructuralFeature.isChangeable(), ItemPropertyDescriptor.GENERIC_VALUE_IMAGE, getTypeText(object), filterFlags));
		}

		return itemPropertyDescriptors;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ReflectiveItemProvider#notifyChanged(org
	 * .eclipse.emf.common.notify.Notification)
	 */
	@Override
	public void notifyChanged(Notification notification) {
		fireNotifyChanged(new ViewerNotification(notification, UMLUtil.getBaseElement((EObject) notification.getNotifier()), true, false));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ReflectiveItemProvider#getCreateChildText
	 * (java.lang.Object, java.lang.Object, java.lang.Object,
	 * java.util.Collection)
	 */
	@Override
	public String getCreateChildText(Object owner, Object feature, Object child, Collection selection) {
		Object childFeature = feature;
		Object childObject = child;

		boolean qualify = childFeature == UMLPackage.Literals.CLASSIFIER__OWNED_USE_CASE || childFeature == UMLPackage.Literals.CLASS__NESTED_CLASSIFIER || childFeature == UMLPackage.Literals.BEHAVIORED_CLASSIFIER__OWNED_BEHAVIOR;

		if (qualify) {
			return getString("_UI_CreateChild_text2", new Object[] { getTypeText(childObject), getFeatureText(childFeature), getTypeText(owner) });
		}
		return super.getCreateChildText(owner, feature, child, selection);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ReflectiveItemProvider#getImage(java.lang
	 * .Object)
	 */
	@Override
	public Object getImage(Object object) {
		return overlayImage(object, getResourceLocator().getImage("full/obj16/Stereotype"));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ReflectiveItemProvider#getText(java.lang
	 * .Object)
	 */
	@Override
	public String getText(Object object) {
		EObject eObject = (EObject) object;
		EClass eClass = eObject.eClass();
		String name = eClass.getName();
		String label = format(capName(name), ' ');
		EStructuralFeature feature = getLabelFeature(eClass);
		if (feature != null) {
			Object value = eObject.eGet(feature);
			if (value != null) {
				return label + " " + value.toString();
			}
		}
		return label;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ReflectiveItemProvider#format(java.lang
	 * .String, char)
	 */
	@Override
	public String format(String name, char separator) {
		name = name.substring(name.lastIndexOf('_') + 1);
		String[] parts = name.split("[A-Z]");
		if (parts.length > 0 && parts[0] != null && parts[0].length() > 0) {
			return name.substring(parts[0].length());
		} else {
			return name;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.emf.edit.provider.ItemProviderAdapter#getResourceLocator()
	 */
	@Override
	public ResourceLocator getResourceLocator() {
		return UMLEditPlugin.INSTANCE;
	}

}
